2 ==============================================================================
4 This file was auto-generated by the Jucer!
6 It contains the basic startup code for a Juce application.
8 ==============================================================================
11 #include "PluginProcessor.h"
12 #include "PluginEditor.h"
14 //==============================================================================
15 /** A demo synth sound that's just a basic sine wave.. */
16 class SineWaveSound
: public SynthesiserSound
23 bool appliesToNote (const int /*midiNoteNumber*/) { return true; }
24 bool appliesToChannel (const int /*midiChannel*/) { return true; }
27 //==============================================================================
28 /** A simple demo synth voice that just plays a sine wave.. */
29 class SineWaveVoice
: public SynthesiserVoice
38 bool canPlaySound (SynthesiserSound
* sound
)
40 return dynamic_cast <SineWaveSound
*> (sound
) != 0;
43 void startNote (const int midiNoteNumber
, const float velocity
,
44 SynthesiserSound
* /*sound*/, const int /*currentPitchWheelPosition*/)
47 level
= velocity
* 0.15;
50 double cyclesPerSecond
= MidiMessage::getMidiNoteInHertz (midiNoteNumber
);
51 double cyclesPerSample
= cyclesPerSecond
/ getSampleRate();
53 angleDelta
= cyclesPerSample
* 2.0 * double_Pi
;
56 void stopNote (const bool allowTailOff
)
60 // start a tail-off by setting this flag. The render callback will pick up on
61 // this and do a fade out, calling clearCurrentNote() when it's finished.
63 if (tailOff
== 0.0) // we only need to begin a tail-off if it's not already doing so - the
64 // stopNote method could be called more than once.
69 // we're being told to stop playing immediately, so reset everything..
76 void pitchWheelMoved (const int /*newValue*/)
78 // can't be bothered implementing this for the demo!
81 void controllerMoved (const int /*controllerNumber*/, const int /*newValue*/)
83 // not interested in controllers in this case.
86 void renderNextBlock (AudioSampleBuffer
& outputBuffer
, int startSample
, int numSamples
)
88 if (angleDelta
!= 0.0)
92 while (--numSamples
>= 0)
94 const float currentSample
= (float) (sin (currentAngle
) * level
* tailOff
);
96 for (int i
= outputBuffer
.getNumChannels(); --i
>= 0;)
97 *outputBuffer
.getSampleData (i
, startSample
) += currentSample
;
99 currentAngle
+= angleDelta
;
104 if (tailOff
<= 0.005)
115 while (--numSamples
>= 0)
117 const float currentSample
= (float) (sin (currentAngle
) * level
);
119 for (int i
= outputBuffer
.getNumChannels(); --i
>= 0;)
120 *outputBuffer
.getSampleData (i
, startSample
) += currentSample
;
122 currentAngle
+= angleDelta
;
130 double currentAngle
, angleDelta
, level
, tailOff
;
134 //==============================================================================
135 JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
136 : delayBuffer (2, 12000)
138 // Set up some default values..
145 lastPosInfo
.resetToDefault();
148 // Initialise the synth...
149 for (int i
= 4; --i
>= 0;)
150 synth
.addVoice (new SineWaveVoice()); // These voices will play our custom sine-wave sounds..
152 synth
.addSound (new SineWaveSound());
155 JuceDemoPluginAudioProcessor::~JuceDemoPluginAudioProcessor()
159 //==============================================================================
160 int JuceDemoPluginAudioProcessor::getNumParameters()
162 return totalNumParams
;
165 float JuceDemoPluginAudioProcessor::getParameter (int index
)
167 // This method will be called by the host, probably on the audio thread, so
168 // it's absolutely time-critical. Don't use critical sections or anything
169 // UI-related, or anything at all that may block in any way!
172 case gainParam
: return gain
;
173 case delayParam
: return delay
;
174 default: return 0.0f
;
178 void JuceDemoPluginAudioProcessor::setParameter (int index
, float newValue
)
180 // This method will be called by the host, probably on the audio thread, so
181 // it's absolutely time-critical. Don't use critical sections or anything
182 // UI-related, or anything at all that may block in any way!
185 case gainParam
: gain
= newValue
; break;
186 case delayParam
: delay
= newValue
; break;
191 const String
JuceDemoPluginAudioProcessor::getParameterName (int index
)
195 case gainParam
: return "gain";
196 case delayParam
: return "delay";
200 return String::empty
;
203 const String
JuceDemoPluginAudioProcessor::getParameterText (int index
)
205 return String (getParameter (index
), 2);
208 //==============================================================================
209 void JuceDemoPluginAudioProcessor::prepareToPlay (double sampleRate
, int /*samplesPerBlock*/)
211 // Use this method as the place to do any pre-playback
212 // initialisation that you need..
213 synth
.setCurrentPlaybackSampleRate (sampleRate
);
214 keyboardState
.reset();
218 void JuceDemoPluginAudioProcessor::releaseResources()
220 // When playback stops, you can use this as an opportunity to free up any
221 // spare memory, etc.
222 keyboardState
.reset();
225 void JuceDemoPluginAudioProcessor::reset()
227 // Use this method as the place to clear any delay lines, buffers, etc, as it
228 // means there's been a break in the audio's continuity.
232 void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer
& buffer
, MidiBuffer
& midiMessages
)
234 const int numSamples
= buffer
.getNumSamples();
237 // Go through the incoming data, and apply our gain to it...
238 for (channel
= 0; channel
< getNumInputChannels(); ++channel
)
239 buffer
.applyGain (channel
, 0, buffer
.getNumSamples(), gain
);
241 // Now pass any incoming midi messages to our keyboard state object, and let it
242 // add messages to the buffer if the user is clicking on the on-screen keys
243 keyboardState
.processNextMidiBuffer (midiMessages
, 0, numSamples
, true);
245 // and now get the synth to process these midi events and generate its output.
246 synth
.renderNextBlock (buffer
, midiMessages
, 0, numSamples
);
248 // Apply our delay effect to the new output..
249 for (channel
= 0; channel
< getNumInputChannels(); ++channel
)
251 float* channelData
= buffer
.getSampleData (channel
);
252 float* delayData
= delayBuffer
.getSampleData (jmin (channel
, delayBuffer
.getNumChannels() - 1));
255 for (int i
= 0; i
< numSamples
; ++i
)
257 const float in
= channelData
[i
];
258 channelData
[i
] += delayData
[dp
];
259 delayData
[dp
] = (delayData
[dp
] + in
) * delay
;
260 if (++dp
> delayBuffer
.getNumSamples())
267 // In case we have more outputs than inputs, we'll clear any output
268 // channels that didn't contain input data, (because these aren't
269 // guaranteed to be empty - they may contain garbage).
270 for (int i
= getNumInputChannels(); i
< getNumOutputChannels(); ++i
)
271 buffer
.clear (i
, 0, buffer
.getNumSamples());
273 // ask the host for the current time so we can display it...
274 AudioPlayHead::CurrentPositionInfo newTime
;
276 if (getPlayHead() != 0 && getPlayHead()->getCurrentPosition (newTime
))
278 // Successfully got the current time from the host..
279 lastPosInfo
= newTime
;
283 // If the host fails to fill-in the current time, we'll just clear it to a default..
284 lastPosInfo
.resetToDefault();
288 //==============================================================================
289 AudioProcessorEditor
* JuceDemoPluginAudioProcessor::createEditor()
291 return new JuceDemoPluginAudioProcessorEditor (this);
294 //==============================================================================
295 void JuceDemoPluginAudioProcessor::getStateInformation (MemoryBlock
& destData
)
297 // You should use this method to store your parameters in the memory block.
298 // Here's an example of how you can use XML to make it easy and more robust:
300 // Create an outer XML element..
301 XmlElement
xml ("MYPLUGINSETTINGS");
303 // add some attributes to it..
304 xml
.setAttribute ("uiWidth", lastUIWidth
);
305 xml
.setAttribute ("uiHeight", lastUIHeight
);
306 xml
.setAttribute ("gain", gain
);
307 xml
.setAttribute ("delay", delay
);
309 // then use this helper function to stuff it into the binary blob and return it..
310 copyXmlToBinary (xml
, destData
);
313 void JuceDemoPluginAudioProcessor::setStateInformation (const void* data
, int sizeInBytes
)
315 // You should use this method to restore your parameters from this memory block,
316 // whose contents will have been created by the getStateInformation() call.
318 // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
319 ScopedPointer
<XmlElement
> xmlState (getXmlFromBinary (data
, sizeInBytes
));
323 // make sure that it's actually our type of XML object..
324 if (xmlState
->hasTagName ("MYPLUGINSETTINGS"))
326 // ok, now pull out our parameters..
327 lastUIWidth
= xmlState
->getIntAttribute ("uiWidth", lastUIWidth
);
328 lastUIHeight
= xmlState
->getIntAttribute ("uiHeight", lastUIHeight
);
330 gain
= (float) xmlState
->getDoubleAttribute ("gain", gain
);
331 delay
= (float) xmlState
->getDoubleAttribute ("delay", delay
);
336 const String
JuceDemoPluginAudioProcessor::getInputChannelName (const int channelIndex
) const
338 return String (channelIndex
+ 1);
341 const String
JuceDemoPluginAudioProcessor::getOutputChannelName (const int channelIndex
) const
343 return String (channelIndex
+ 1);
346 bool JuceDemoPluginAudioProcessor::isInputChannelStereoPair (int /*index*/) const
351 bool JuceDemoPluginAudioProcessor::isOutputChannelStereoPair (int /*index*/) const
356 bool JuceDemoPluginAudioProcessor::acceptsMidi() const
358 #if JucePlugin_WantsMidiInput
365 bool JuceDemoPluginAudioProcessor::producesMidi() const
367 #if JucePlugin_ProducesMidiOutput
374 //==============================================================================
375 // This creates new instances of the plugin..
376 AudioProcessor
* JUCE_CALLTYPE
createPluginFilter()
378 return new JuceDemoPluginAudioProcessor();